package com.sjh.baseutils

import org.json.JSONArray
import org.json.JSONObject
import java.net.URLEncoder
import java.util.*

/**
 * kotlin中实现的一些php中的方法
 * @author Extends
 * @date 2020/9/29
 */

/**
 * 使用php的ksort方法
 * 支持自定义类型，但不推荐这么干，毕竟反射效率不高
 */
fun phpKsort(data:Array<*>):SortedMap<String,Any>{
    val map:SortedMap<String,Any> = TreeMap<String,Any>()

    data.forEachIndexed { index, any ->
        map[index.toString()] = ksortValue(any)
    }

    return map
}

/**
 * 使用php的ksort方法
 *
 * 支持自定义类型，但不推荐这么干，毕竟反射效率不高
 */
fun phpKsort(data:Iterable<*>):SortedMap<String,Any>{
    val map:SortedMap<String,Any> = TreeMap<String,Any>()

    data.forEachIndexed { index, any ->
        map[index.toString()] = ksortValue(any)
    }

    return map
}

/**
 * 使用php的ksort方法
 *
 * 支持自定义类型，但不推荐这么干，毕竟反射效率不高
 */
fun phpKsort(data:Map<*,*>): SortedMap<String,Any> {
    val map:SortedMap<String,Any> = TreeMap<String,Any>()
    data.forEach {
        map[it.key.toString()] = ksortValue(it.value)
    }
    return map
}

fun phpKsort(data:JSONObject):SortedMap<String,Any>{
    val map:SortedMap<String,Any> = TreeMap<String,Any>()
    data.keys().forEach {
        val value = data.get(it)
        if(value is JSONObject){
            map[it] = phpKsort(value)
        }else if(value is JSONArray){
            map[it] = phpKsort(value)
        }else{
            map[it] = value.toString()
        }
    }
    return map
}

fun phpKsort(data: JSONArray):SortedMap<String,Any>{
    val map:SortedMap<String,Any> = TreeMap<String,Any>()
    ( 0 until data.length()).forEach {
        val value = data.get(it)
        if(value is JSONObject){
            map[it.toString()] = phpKsort(value)
        }else if(value is JSONArray){
            map[it.toString()] = phpKsort(value)
        }else{
            map[it.toString()] = value.toString()
        }
    }
    return map
}

/**
 * 处理ksort排序过程中的value值
 */
private fun ksortValue(value:Any?):Any = when(value){
    null -> ""
    is Array<*> -> phpKsort(value)
    is Iterable<*> -> phpKsort(value)
    is Map<*,*> -> phpKsort(value)
    is Number -> value
    is CharSequence -> value
    is Char -> value
    is Boolean -> value
    else -> phpKsort(
        objectToMap(
            value
        )
    )
}

/**
 * 使用php的http_build_query方法
 *
 * 支持自定义类型，但不推荐这么干，毕竟反射效率不高
 */
fun phpHttpBuildQuery(data:Map<*,*>):String{
    val sb = StringBuilder()
    var index = 0
    data.forEach {
        if(index != 0){
            sb.append("&")
        }
        val value =
            phpHttpBuildQueryValue(it.value, it.key.toString())
        httpBuildQueryStringBuilder(
            sb,
            it.key.toString(),
            value
        )
        index ++
    }
    val reString = sb.toString()

    return URLEncoder.encode(reString,Charsets.UTF_8.name()).replace("%3D", "=").replace("%26", "&")
}


private fun phpHttpBuildQuery(data:Map<*,*>,pre:String):String{
    val sb = StringBuilder()
    var index = 0
    data.forEach {
        if(index != 0){
            sb.append("&")
        }
        val key = "$pre[${it.key}]"

        val value = phpHttpBuildQueryValue(it.value, key)
        httpBuildQueryStringBuilder(sb, key, value)
        index ++
    }
    return sb.toString()
}

private fun phpHttpBuildQuery(data:Array<*>,pre:String):String{
    val sb = StringBuilder()
    data.forEachIndexed { index, any ->
        if(index != 0){
            sb.append("&")
        }
        val key = "$pre[$index]"
        val value = phpHttpBuildQueryValue(any, key)
        httpBuildQueryStringBuilder(sb, key, value)
    }
    return sb.toString()
}

private fun phpHttpBuildQuery(data:Iterable<*>,pre:String):String{
    val sb = StringBuilder()
    data.forEachIndexed { index, any ->
        if(index != 0){
            sb.append("&")
        }
        val key = "$pre[$index]"
        val value = phpHttpBuildQueryValue(any, key)
        httpBuildQueryStringBuilder(sb, key, value)
    }
    return sb.toString()
}

private fun phpHttpBuildQueryValue(value:Any?,pre: String):Pair<Boolean,String>? = when(value){
    null -> null
    is Array<*> -> false to phpHttpBuildQuery(value, pre)
    is Iterable<*> -> false to phpHttpBuildQuery(value, pre)
    is Map<*,*> -> false to phpHttpBuildQuery(value, pre)
    is Number -> true to value.toString()
    is CharSequence -> true to value.toString()
    is Char -> true to value.toString()
    is Boolean -> true to value.toString()
    else -> false to phpHttpBuildQuery(
        objectToMap(
            value
        ), pre
    )
}

private fun httpBuildQueryStringBuilder(sb:StringBuilder,key:String,pair:Pair<Boolean,String>?){
    if(null != pair){
        if(pair.first){
            sb.append("$key=${pair.second}")
        }else{
            sb.append(pair.second)
        }
    }
}

private fun objectToMap(requestParameters: Any): Map<String, Any> {

    val map = HashMap<String, Any>()
    try {
        // 获取f对象对应类中的所有属性域
        val fields = requestParameters.javaClass.declaredFields
        var i = 0
        val len = fields.size
        while (i < len) {
            val varName = fields[i].name
            // 获取原来的访问控制权限
            val accessFlag = fields[i].isAccessible
            // 修改访问控制权限
            fields[i].isAccessible = true
            // 获取在对象f中属性fields[i]对应的对象中的变量
            val o = fields[i].get(requestParameters)
            if (!o?.toString().isNullOrBlank()) {
                map[varName] = o.toString().trim { it <= ' ' }
                // 恢复访问控制权限
                fields[i].isAccessible = accessFlag
            }
            i++
        }
    }catch (e:Exception){
        e.printStackTrace()
    }

    return map
}


